//Copyright (c) 2024 Deng Zicheng
//        "CarController" is licensed under Mulan PSL v2.
//        You can use this software according to the terms and conditions of the Mulan PSL v2.
//        You may obtain a copy of Mulan PSL v2 at:
//        http://license.coscl.org.cn/MulanPSL2
//        THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
//        See the Mulan PSL v2 for more details.
package com.sinan.myapplication;

import ohos.aafwk.ability.Ability;
import ohos.aafwk.content.Intent;
import ohos.app.Context;
import ohos.rpc.*;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import ohos.utils.zson.ZSONObject;

import java.util.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


/**
 * 蓝牙管理ServiceAbility
 */
public class bleBTServiceAbility extends Ability{
    private static final HiLogLabel LABEL_LOG = new HiLogLabel(3, 0xD001100, "LOG");

    private static Context context;
    private final Remote remote = new Remote();



    @Override
    public void onStart(Intent intent) {
        HiLog.error(LABEL_LOG, "bleBTServiceAbility::onStart");
        super.onStart(intent);
    }

    @Override
    public void onBackground() {
        super.onBackground();
        HiLog.info(LABEL_LOG, "bleBTServiceAbility::onBackground");
    }

    @Override
    public void onStop() {
        super.onStop();
        HiLog.info(LABEL_LOG, "bleBTServiceAbility::onStop");
    }

    @Override
    public void onCommand(Intent intent, boolean restart, int startId) {
    }

    /**
     * 返回交互对象
     */
    @Override
    public IRemoteObject onConnect(Intent intent) {
        super.onConnect(intent);
        return remote.asObject();
    }

    @Override
    public void onDisconnect(Intent intent) {
    }

    public static void setContextMain(Context context) {
        bleBTServiceAbility.context = context;
    }

    public static Context getContextMain(){
        return context;
    }

    /**
     * js调用java PA
     */
    public static class Remote extends RemoteObject implements IRemoteBroker {
        //状态码
        private static final int SUCCESS = 0;
        private static final int ERROR = 1;

        //操作码
        private static final int CALL = 1001;

        //通信码
        private static final int SUBSCRIBE_AUTO = 1003;
        private static final int UNSUBSCRIBE_AUTO = 1004;
        private static final int SUBSCRIBE_USER = 1005;
        private static final int UNSUBSCRIBE_USER = 1006;

        //行为码
        private static final int SCAN = 0;
        private static final int DEVICES = 1;
        private static final int CONNECT=2;


        //回应码
        private static final String STATE="S_";
        private static final String STATE_SPEED_BLOCK_POWER ="S_S";

        private static final String STATE_LOCATION_DIRECTION ="S_LD";

        private static final String STATE_INIT="S_I";
        //应答码
        private static final String COPY="C_";
        private static final String COPY_SPEED_DEGREE="C_SD";
        private static final String COPY_MOD_CHANGE="C_MC";
        private static final String COPY_STOP="C_S";

        private static final String COPY_DESTINATION="C_D";



        //蓝牙中心管理设备
        private static final BlueTooth_BLE_Manager blueToothBleManager=new BlueTooth_BLE_Manager(bleBTServiceAbility.getContextMain());

        //订阅对象存储
        private static IRemoteObject remoteObjectHandler_User;
        private static IRemoteObject remoteObjectHandler_Auto;

        //线程锁
        private boolean notify_thread_key =false;
        private boolean dealWithMessages_thread_key =false;

        //控制信号缓存
        private final AksCopy speedAndDegree_AC =new AksCopy();

        private final AksCopy modChange_AC =new AksCopy();

        private final AksCopy stop_AC =new AksCopy();

//        private final AksCopy light_AC =new AksCopy();

        private final AksCopy destination_AC=new AksCopy();


        Remote() {
            super("BlueService_Remote");
        }

        private static final List<String> messages=new LinkedList<>();

        public static Lock messageLock=new ReentrantLock();
        private String address="";


        /**
         * js FA请求处理java PA
         * @param code 请求形式
         * @param data 操作数据
         * @param reply 回复对象
         * @param option 操作
         * @return 请求是否成功
         */
        @Override
        public boolean onRemoteRequest(int code, MessageParcel data, MessageParcel reply, MessageOption option) {
            Map<String, Object> result = new HashMap<>();
            try{
                if (code == CALL) {
                    String dataStr = data.readString();
                    RequestParam param;
                    param = ZSONObject.stringToClass(dataStr, RequestParam.class);
                    result.put("code", SUCCESS);
                    switch (param.getOption()) {
                        case "scan"://执行扫描
                            blueToothBleManager.scanBLE();
                            result.put("type", SCAN);
                            break;
                        case "scanStop"://停止扫描
                            blueToothBleManager.scanStopBLE();
                            break;
                        case "devices"://获取扫描到的设备
                            result.put("devices", blueToothBleManager.getAllDevice());
                            result.put("type", DEVICES);
                            break;
                        case "connect"://连接设备
                            this.address=param.getAddress();
                            blueToothBleManager.connect(this.address);
                            result.put("type", CONNECT);
                            break;
                        case "control"://设备控制速度与角度
                            String speedAndDegreeControlMessage = String.format("CTRL_%05d%03d",param.getSpeed(),param.getDegree());
                            this.speedAndDegree_AC.setValue(speedAndDegreeControlMessage);
                            break;
                        case "mod"://切换模式
                            int modCode = param.getCode();
                            String message;
                            if (modCode==1){
                                message="USER_";
                                //清除自动模式未执行命令
                                this.destination_AC.setCopied();
                                this.stop_AC.setCopied();
                                this.modChange_AC.setValue(message);
                            }else if (modCode==0){
                                message="AUTO_";
                                //清除用户未执行命令
                                this.speedAndDegree_AC.setCopied();
//                                this.light_AC.setCopied();
                                this.stop_AC.setCopied();
                                this.modChange_AC.setValue(message);
                            }else {
                                this.modChange_AC.setRecopy();
                            }
                            break;
                        case "stop"://停止
                            this.stop_AC.setValue("STOP_");
                            this.stop_AC.allowAcceptSameVale(false);//禁止执行重复命令
                            break;
                        case "start"://重启行动
                            this.stop_AC.allowAcceptSameVale(true);//允许执行相同命令
                            this.speedAndDegree_AC.setRecopy();
                            break;
                        case "begin_auto"://开始自动行驶
                            this.stop_AC.allowAcceptSameVale(true);//允许执行相同命令
                            int destinationX = param.getDestination_X();
                            int destinationY = param.getDestination_Y();
                            String format = String.format("START%d:%d#", destinationX,destinationY);
                            this.destination_AC.setValue(format);
                            this.destination_AC.allowAcceptSameVale(true);
                            break;
                    }
                    reply.writeString(ZSONObject.toZSONString(result));
                }if(code== SUBSCRIBE_USER) {
                    //用户界面订阅
                    Remote.remoteObjectHandler_User =data.readRemoteObject();
                    //开启请求设备信息
                    if (!this.notify_thread_key){
                        startNotify();
                    }
                    //开启处理设备信息
                    if (!this.dealWithMessages_thread_key){
                        startDealWithMessages();
                    }
                    result.put("code", SUCCESS);
                    reply.writeString(ZSONObject.toZSONString(result));
                }else if(code== SUBSCRIBE_AUTO) {
                    //自动行驶界面订阅
                    Remote.remoteObjectHandler_Auto =data.readRemoteObject();
                    result.put("code", SUCCESS);
                    reply.writeString(ZSONObject.toZSONString(result));
                }else if(code== UNSUBSCRIBE_USER){
                    //用户界面取消订阅
                    Remote.remoteObjectHandler_User =null;
                    this.notify_thread_key =false;//停止通知提醒线程
                    this.dealWithMessages_thread_key=false;//停止处理接收信息线程
                    result.put("code", SUCCESS);
                    reply.writeString(ZSONObject.toZSONString(result));
                }else if(code== UNSUBSCRIBE_AUTO){
                    //自动行驶界面取消订阅
                    Remote.remoteObjectHandler_Auto =null;//删除订阅对象
                    result.put("code", SUCCESS);
                    reply.writeString(ZSONObject.toZSONString(result));
                }
                return true;
            }catch (Exception e){
                result.put("abilityError", ERROR);
                reply.writeString(ZSONObject.toZSONString(result));
                return false;
            }
        }

        /**
         * 设备信息询问提醒
         */
        public void startNotify() {
            this.notify_thread_key =true;
            Thread thread_startNotify = new Thread(() -> {
                while (this.notify_thread_key) {
                    try {
                        if (BlueTooth_BLE_Manager.isConnect_State()) {
                            /* 未执行命令重放 */
                            if (this.modChange_AC.isNotCopy()) {
                                blueToothBleManager.bleWrite(this.modChange_AC.getValue());
                            }else if (this.stop_AC.isNotCopy()) {
                                blueToothBleManager.bleWrite(this.stop_AC.getValue());
                            }else if (this.destination_AC.isNotCopy()) {
                                blueToothBleManager.bleWrite(this.destination_AC.getValue());
                            }else if (this.speedAndDegree_AC.isNotCopy()) {
                                blueToothBleManager.bleWrite(this.speedAndDegree_AC.getValue());
                            }
                            Thread.sleep(50);
                        }
                    } catch (InterruptedException ignored) {
                    }
                }
            });
            thread_startNotify.start();
        }

        /**
         * 设备信息处理与超时未反应重连
         */
        private void startDealWithMessages() {
            this.dealWithMessages_thread_key=true;
            Thread thread_messagesDealWith = new Thread(() -> {
                int wait_counter = 0;
                while (this.dealWithMessages_thread_key) {
                    blueToothBleManager.readRSSI();
                    ResponseParam responseParamState=new ResponseParam();
                    responseParamState.setType("connection");
                    if (BlueTooth_BLE_Manager.isConnect_State()){
                        responseParamState.setNum1(1);
                        bleBTServiceAbility.Remote.updateToJs(responseParamState);
                    }else{
                        responseParamState.setNum1(0);
                        bleBTServiceAbility.Remote.updateToJs(responseParamState);
                    }
                    //如果有消息
                    if (!Remote.messages.isEmpty()) {
                        wait_counter = 0;
                        ResponseParam responseParam = new ResponseParam();
                        Remote.messageLock.lock();
                        String msg = Remote.messages.remove(0);
                        Remote.messageLock.unlock();
                        try {
                            int end =msg.length();
                            int begin = msg.indexOf(':') + 1;
                            String substring = msg.substring(begin, end);
                            if(msg.startsWith(STATE_INIT)){
                                responseParam.setType(STATE_INIT);
                                responseParam.setNum1(Integer.parseInt(substring));
                                Remote.updateToJs(responseParam);
                                continue;
                            }
                            //处理基本设备状态信息
                            if (msg.startsWith(STATE)) {
                                //收到速度信息
                                if (msg.startsWith(STATE_SPEED_BLOCK_POWER)) {
                                    responseParam.setType(STATE_SPEED_BLOCK_POWER);
                                    String[] split = substring.split("~");
                                    responseParam.setNum1(Integer.parseInt(split[1]));//阻碍状态
                                    responseParam.setNum3(Double.parseDouble(split[0]));//速度
                                    responseParam.setNum2(Integer.parseInt(split[2]));//电量
                                }else if(msg.startsWith(STATE_LOCATION_DIRECTION)){
                                    responseParam.setType(STATE_LOCATION_DIRECTION);
                                    String[] split = substring.split("~");
                                    responseParam.setNum1(Integer.parseInt(split[0]));//朝向
                                    responseParam.setNum3(Double.parseDouble(split[1]));
                                    responseParam.setNum4(Double.parseDouble(split[2]));
                                }
                                Remote.updateToJs(responseParam);
                            } else if (msg.startsWith(COPY)) {//处理命令执行应答信息
                                //获取uuid判断应答是否正确
                                if (msg.startsWith(COPY_SPEED_DEGREE)) {
                                    this.speedAndDegree_AC.copyEqualThenClearUUID(substring);
                                } else if (msg.startsWith(COPY_MOD_CHANGE)) {
                                    this.modChange_AC.copyEqualThenClearUUID(substring);
                                } else if (msg.startsWith(COPY_STOP)) {
                                    this.stop_AC.copyEqualThenClearUUID(substring);
                                } else if (msg.startsWith(COPY_DESTINATION)) {
                                    this.destination_AC.copyEqualThenClearUUID(substring);
                                }
                            }

                        } catch (Exception ignore) {
                        }

                    } else if (BlueTooth_BLE_Manager.isConnect_State()) {//无响应处理
                        wait_counter++;
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                        if (wait_counter == 6) {//无响应超时重连
                            wait_counter = 0;
                            blueToothBleManager.connect(this.address);
                        }
                    }

                }
            });
            thread_messagesDealWith.start();
        }

        /**
         * 添加设备消息进入处理队列
         * @param msg 消息
         */
        public static void addMessage(String msg){
            Remote.messages.add(msg);
        }

        /**
         * 通知JS消息
         * @param data 信息
         */
        public static void updateToJs(ResponseParam data){
            MessageParcel messageParcel = MessageParcel.obtain();
            MessageParcel reply = MessageParcel.obtain();
            MessageOption option = new MessageOption();
            messageParcel.writeString(ZSONObject.toZSONString(data));
            try {
                if(Remote.remoteObjectHandler_Auto!=null){//通知auto模式对象消息
                    Remote.remoteObjectHandler_Auto.sendRequest(100, messageParcel, reply, option);
                }
                //通知用户订阅对象消息
                Remote.remoteObjectHandler_User.sendRequest(100, messageParcel, reply, option);
            } catch (RemoteException e) {
                throw new RuntimeException(e);
            }
            reply.reclaim();
            messageParcel.reclaim();

        }


        @Override
        public IRemoteObject asObject() {
            return this;
        }
    }
}

